import {
  Shader,
  ShaderData,
  ShaderProperty,
  ShaderPool,
  ShaderProgram,
  ShaderProgramPool,
  ShaderMacro,
  ShaderMacroCollection,
  ShaderDataGroup,
  ShaderLib
} from "@nirvana/shaders";
import { Vector3, Matrix4 } from "@nirvana/math";

import { WebGLCanvas } from "@nirvana/canvas";
import { VertexBufferData, IndexBufferData, DataElement } from "@nirvana/core";

const shaderMacroCollection: ShaderMacroCollection = new ShaderMacroCollection();
console.log(shaderMacroCollection);
const colorShaderData: ShaderData = new ShaderData(ShaderDataGroup.Material);
console.log(ShaderDataGroup, colorShaderData);
const pool: ShaderProgramPool = new ShaderProgramPool();

// 使用使用 Canvas
let canvas = document.getElementById("engine-nirvana");
const webCanvas = new WebGLCanvas(canvas, {});
const engine = webCanvas.engine;
const gl = engine.gl;
gl.getExtension('OES_standard_derivatives');
const cVS = `
attribute vec3 position;
attribute vec3 aBarycentric;
uniform mat4 rotateMatrix;
varying vec3 vColor;
varying vec3 vBarycentric;
void main(void) { 
  gl_Position = rotateMatrix * vec4(position, 1.);
  vColor = vec3(1.0,1.0,1.0);
  vBarycentric = aBarycentric;
}
`;
const cFS = `
#extension GL_OES_standard_derivatives : enable
varying vec3 vColor;
varying vec3 vBarycentric;
float edgeFactor(){
  vec3 d = fwidth(vBarycentric);
  // 边缘平滑效果
  vec3 a3 = smoothstep(vec3(0.0), d * 7.5, vBarycentric);
  return min(min(a3.x, a3.y), a3.z);
}
float edgeFactor2(){
  vec2 d = fwidth(vBarycentric.yz);
  vec2 a2 = smoothstep(vec2(0.0), d*2.0, vBarycentric.yz);
  return min(a2.x, a2.y);
}
float edgeFactor3(){
  vec3 d = fwidth(vBarycentric);
  vec3 a3 = smoothstep(vec3(0.0), d*2.0, vBarycentric);
  return min(min(a3.x, a3.y), a3.z);
}
float edgeFactor4(){
  vec3 d = fwidth(vBarycentric);
  vec3 a3 = smoothstep(vec3(0.0), d * 30.0 , vBarycentric);
//return min(min(a3.x, a3.y), a3.z);
 return (a3.x + a3.y + a3.z) / 3.0;
}
// float edgeFactor5(){
//   // one way to calculate interpolation factor
//   float f = vBarycentric.x;
//   if( vBarycentric.x < min(vBarycentric.y, vBarycentric.z) )
//       f = vBarycentric.y;

//   const float PI = 3.14159265;
//   float stipple = pow( clamp( 5 * sin( f * 21.0 * PI ), 0.0, 1.0 ), 10.0 );
//   float thickness = 2.0 * stipple;

//   vec3 d = fwidth(vBarycentric);
//   vec3 a3 = smoothstep(vec3(0.0), d * thickness, vBarycentric);
//   return min(min(a3.x, a3.y), a3.z);
// }
void main(void) {
  gl_FragColor = vec4(vColor, 1.0);
  // 1 简单效果
  // if(any(lessThan(vBarycentric, vec3(0.02)))){
  //   gl_FragColor = vec4(vColor, 1.);
  // }else{
  //   gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
  // }
  // // 2 边缘发光
  // float interopter = edgeFactor4();
  // interopter = pow(interopter, 0.5);
  // gl_FragColor.rgb = mix(vec3(1.0,.0,.0), vec3(1.0,1.0,1.0),interopter);
  // gl_FragColor.a = mix(1.0, .0,interopter);
  // // 3 改进效果
  // gl_FragColor.rgb = mix(vec3(0.0), vec3(1.0), edgeFactor());
  // gl_FragColor.a = 1.0;
  // // 透明背影
  // if (gl_FrontFacing) {
  //     gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0 - edgeFactor());
  // } else {
  //   // 淡化背面
  //   gl_FragColor = vec4(0.0, 0.0, 0.0, (1.0 - edgeFactor()) * 0.3);
  // }
}`;
const colorDemo = Shader.create("colorDemo", cVS, cFS);
console.log(colorDemo, Shader.find("colorDemo"));

const program: ShaderProgram = colorDemo.getShaderProgram(engine.gl, shaderMacroCollection, pool);
console.log("color", program);

const vertices: number[] = [
  -0.5, -0.5, -0.5,  0.5, -0.5,-0.5, 0.5, 0.5,-0.5, -0.5, 0.5,-0.5,
  -0.5, -0.5,  0.5,  0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
  -0.5, -0.5, -0.5, -0.5, 0.5,-0.5, -0.5, 0.5, 0.5, -0.5,-0.5, 0.5,
   0.5, -0.5, -0.5,  0.5, 0.5,-0.5, 0.5, 0.5, 0.5, 0.5,-0.5, 0.5,
  -0.5, -0.5, -0.5, -0.5,-0.5, 0.5, 0.5,-0.5, 0.5, 0.5,-0.5,-0.5,
  -0.5,  0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,-0.5, 
];

const indices: number[] = [
  0,1,2, 0,2,3, 4,5,6, 4,6,7,
  8,9,10, 8,10,11, 12,13,14, 12,14,15,
  16,17,18, 16,18,19, 20,21,22, 20,22,23
];

const barycentrics = vertices.map((v, i) => {
  if (i % 9 === 0 || i % 9 === 4 || i % 9 === 8) {
    return 1.0;
  }
  return 0.0;
});

const nIndices: number[] = [];
if (indices.length > 0) {
  for (let i = 0, len = indices.length; i < len; i += 3) {
    const a = indices[i + 0];
    const b = indices[i + 1];
    const c = indices[i + 2];

    nIndices.push(a, b, b, c, c, a);
  }
} else {
  for (let i = 0, l = vertices.length / 3 - 1; i < l; i += 3) {
    const a = i + 0;
    const b = i + 1;
    const c = i + 2;

    nIndices.push(a, b, b, c, c, a);
  }
}

console.log(nIndices);
const vBuffer = new VertexBufferData(new Float32Array(vertices), [
  new DataElement("position", 3, gl.FLOAT, false, 0, 0)
]);
const bBuffer = new VertexBufferData(new Float32Array(barycentrics), [
  new DataElement("aBarycentric", 3, gl.FLOAT, false, 0, 0)
]);
const iBuffer = new IndexBufferData(new Uint16Array(nIndices));
vBuffer.create(gl);
bBuffer.create(gl);
iBuffer.create(gl);

const shaderData: ShaderData = new ShaderData(ShaderDataGroup.Material);
console.log(ShaderDataGroup, shaderData);

let r = 0;
const axis = new Vector3(0.8, 1.0, 0.5);
const rotateMatrix = Matrix4.e;

engine.update = (gl) => {
  r += 0.01;
  rotateMatrix.rotationAxisAngle(axis, r);
  // console.log('--');
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  // 用上面指定的颜色清除缓冲区
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.enable(gl.DEPTH_TEST);
  // gl.disable(gl.DEPTH_WRITEMASK);
  // 设置混合函数
  // gl.enable(gl.BLEND);
  // gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  // gl.enable(gl.CULL_FACE);
  // gl.enable(gl.BLEND);
  // gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  // 颜色 start 三
  program.bind();
  vBuffer.upload(program._glProgram, gl);
  bBuffer.upload(program._glProgram, gl);
  shaderData.setMatrix("rotateMatrix", rotateMatrix);
  program.uploadAll(program.otherUniformBlock, shaderData);
  iBuffer.upload(gl);
  gl.drawElements(gl.LINES, nIndices.length, gl.UNSIGNED_SHORT, 0);
  // gl.drawArrays(gl.LINES, 0, nIndices.length / 3);
  // iBuffer.draw(gl);
};
